package cn.murky.tenant.core.utils;


import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.exception.NotLoginException;
import cn.murky.security.SecurityCache;
import cn.murky.tenant.core.SecurityTenantUserInfo;
import org.noear.solon.Solon;

import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.concurrent.Callable;

import static cn.murky.tenant.core.constant.Constants.TENANT_ID_HEADER;
import static cn.murky.tenant.core.constant.Constants.ZERO;


public class SecurityUtils {
    static SecurityCache<SecurityTenantUserInfo> securityCache;

    static {
        Solon.context().getBeanAsync(SecurityCache.class, systemSecurityCache -> {
            securityCache = systemSecurityCache;
        });
    }

    public static ScopedValue<SecurityTenantUserInfo> SECURITY_USERINFO = ScopedValue.newInstance();

    /**
     * 获取当前登录用户ID
     *
     * @return 用户id
     */
    public static Long getUserId() {
        SecurityTenantUserInfo securityTenantUserInfo = SECURITY_USERINFO.get();
        if (securityTenantUserInfo != null && securityTenantUserInfo.getUserId() != null) {
            return securityTenantUserInfo.getUserId();
        }
        return securityCache.getUserId();
    }

    public static Long getNoExceoptionUserId() {
        try {
            return securityCache.getUserId();
        } catch (Exception ex) {
            return null;
        }
    }

    /**
     * 获取当前登录租户id
     *
     * @return 用户id
     */
    public static Long getTenantId() {
        SecurityTenantUserInfo securityTenantUserInfo = get();
        if (securityTenantUserInfo != null) {
            return securityTenantUserInfo.getTenantId();
        }
        return ZERO;
    }

    /**
     * 设置当前登录租户id
     */
    public static <V> V callTenantId(Long tenantId, Callable<V> runnable) throws Exception {
        SecurityTenantUserInfo securityTenantUserInfo = new SecurityTenantUserInfo()
                .setTenantId(tenantId);
        return ScopedValue.callWhere(SECURITY_USERINFO, securityTenantUserInfo, runnable);
    }

    /**
     * 删除当前登录租户id
     */
    @Deprecated
    public static void deleteTenantId() {
        SaHolder.getStorage().delete(TENANT_ID_HEADER);
    }

    /**
     * 获取当前登录用户信息
     *
     * @return 当前登录用户信息
     */
    public static SecurityTenantUserInfo getUserInfo() throws NotLoginException {
        SecurityTenantUserInfo securityTenantUserInfo = get();
        return Optional.ofNullable(securityTenantUserInfo).orElseGet(() -> securityCache.getUserInfo());
    }

    /**
     * 获取指定token的用户信息
     * @return  token的用户信息
     */
    public static SecurityTenantUserInfo getUserInfo(String token){
        return securityCache.getUserInfo(token);
    }

    public static SecurityTenantUserInfo getUserInfoNoScope() throws NotLoginException {
        return securityCache.getUserInfo();
    }

    /**
     * 保存当前登录用户信息
     *
     * @param securityUser 登录用户信息
     */
    public static void setUserInfo(SecurityTenantUserInfo securityUser) {
        securityCache.setUserInfo(securityUser);
    }

    /**
     * 修改当前登录用户信息
     */
    public static void delUserInfo() {
        securityCache.delUserInfo();
    }

    public static Boolean isAdmin() throws NotLoginException {
        return securityCache.admin();
    }

    public static void runnable(SecurityTenantUserInfo securityTenantUserInfo, Runnable runnable) {
        ScopedValue.runWhere(SECURITY_USERINFO, securityTenantUserInfo, runnable);
    }

    public static <V> V callable(SecurityTenantUserInfo securityTenantUserInfo, Callable<V> callable) throws Exception {
        return ScopedValue.callWhere(SECURITY_USERINFO, securityTenantUserInfo, callable);
    }

    private static SecurityTenantUserInfo get() {
        try {
            return SECURITY_USERINFO.get();
        } catch (NoSuchElementException e) {
            return null;
        }
    }

}
